/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.framework;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.aopalliance.intercept.Interceptor;
import org.aopalliance.intercept.MethodInterceptor;

import org.springframework.aop.Advisor;
import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.IntroductionAwareMethodMatcher;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
import org.springframework.lang.Nullable;

/**
 * A simple but definitive way of working out an advice chain for a Method,
 * given an {@link Advised} object. Always rebuilds each advice chain;
 * caching can be provided by subclasses.
 *
 * @author Juergen Hoeller
 * @author Rod Johnson
 * @author Adrian Colyer
 * @since 2.0.3
 */
@SuppressWarnings("serial")
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

	@Override
	/**
	 * 查找处理适合当前方法的拦截器列表
	 * config:ProxyFactory
	 *
	 * config：AOP 代理工厂配置类接口。提供了操作和管理 Advice(通知) 和 Advisor(通知者) 的能力
	 * method：方法对象
	 * targetClass：类对象  可以为null
	 *
	 * 在aop配置中，根据targetClass和method查找对应的拦截器列表
	 *
	 *
	 *
	 */
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		//AdvisorAdapterRegistry两个作用:1.注册AdvisorAdapter   2.根据AdvisorAdapter获取MethodInterceptor
		//AdvisorAdapterRegistry用于保存AdvisorAdapter的注册中心，
		//其中AdvisorAdapter是用来将Advisor转为MethodInterceptor的
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

		//获取ProxyFactory内的所有Advisor：1.addAdvice(Advice advice)  2.addAdvisor(Advisor advisor)
		//Advisor添加到config时机？
		Advisor[] advisors = config.getAdvisors();

		//定义一个集合用于保存AdvisorAdapter转换后生成的MethodInterceptor
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		//引介增强
		Boolean hasIntroductions = null;

		for (Advisor advisor : advisors) {
			//切点增强
			///处理PointcutAdvisor类型的Advisor，即带切入点的Advisor
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				//转换成可以获取切点信息的类型
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				//判断是否为切点类
				//config.isPreFiltered() 是否对此代理配置进行预过滤，以便只有包含适合的通知者(匹配代理的目标类)，设置为true，表示在构建用于代理调用的实际通知者链时，可以跳过 ClassFilter 检查
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					//引介增强
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					//判断是否匹配切点方法
					else {
						match = mm.matches(method, actualClass);
					}
					//静态匹配成功，再检查是否动态匹配
					if (match) {
						//关键:提取拦截器
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								//动态匹配
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						//拦截器加入集合中
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			//引介增强
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			//如果不是PointcutAdvisor，每一个Advisor对应的拦截器列表都添加到interceptorList，即默认匹配所有类和方法
			//处理其他类型的，例如PrototypePlaceholderAdvisor或自定义的Advisor
			else {
				//DefaultAdvisorAdapterRegistry(构造方法) 默认提供了MethodBeforeAdviceAdapter、AfterReturningAdviceAdapterThrowsAdviceAdapter
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

	/**
	 * Determine whether the Advisors contain matching introductions.
	 * //用于判断AdvisedSupport中的advisors是否有是IntroductionAdvisor类型的
	 */
	private static boolean hasMatchingIntroductions(Advisor[] advisors, Class<?> actualClass) {
		for (Advisor advisor : advisors) {
			if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (ia.getClassFilter().matches(actualClass)) {
					return true;
				}
			}
		}
		return false;
	}

}
